package org.distributed.transaction.core.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.distributed.transaction.core.annotion.ProxyTransaction;
import org.distributed.transaction.core.annotion.TccTransaction;
import org.distributed.transaction.core.context.TccTransactionInfo;
import org.distributed.transaction.core.context.TransactionContext;
import org.distributed.transaction.core.context.TransactionInfo;
import org.distributed.transaction.core.enums.DTTransactionType;
import org.distributed.transaction.core.interceptor.TransactionInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 分布式事务切面。 proxy connection 模式的； tcc模式的。
 */
@Aspect
@Component
public class TransactionAspect {

	@Autowired
	private TransactionInterceptor transactionInterceptor;

	@Pointcut("@annotation(org.distributed.transaction.core.annotion.TccTransaction)")
	public void tccTransactionPointcut() {
	}

	@Pointcut("@annotation(org.distributed.transaction.core.annotion.ProxyTransaction)")
	public void proxyTransactionPointcut() {
	}

	@Around("tccTransactionPointcut()")
	public void invokeTccTransaction(ProceedingJoinPoint point) throws Throwable {
		/**
		 * 创建事务上下文
		 */
		TransactionContext transactionContext = TransactionContext.get();
		// 保存事务类型
		transactionContext.setDtTransactionType(DTTransactionType.TCC);

		// 保存事务信息
		TransactionInfo tccransactionInfo = new TccTransactionInfo(point);
		transactionContext.setTransactionInfo(tccransactionInfo);

		Method bussinessMethod = tccransactionInfo.getBusinessMethod();
		TccTransaction tccTransaction = bussinessMethod.getAnnotation(TccTransaction.class);
		transactionContext.setPropagation(tccTransaction.propagation());
		transactionContext.setBusinessCallback(point::proceed);
		transactionInterceptor.doInvokeTransaction(transactionContext);
	}

	@Around("proxyTransactionPointcut()")
	public void invokeProxyTransaction(ProceedingJoinPoint point) throws Throwable {
		/**
		 * 创建事务上下文
		 */
		TransactionContext transactionContext = TransactionContext.get();
		// 保存事务类型
		transactionContext.setDtTransactionType(DTTransactionType.Proxy);

		// 保存事务信息
		TransactionInfo transactionInfo = new TransactionInfo(point);
		transactionContext.setTransactionInfo(transactionInfo);

		Method bussinessMethod = transactionInfo.getBusinessMethod();

		ProxyTransaction proxyTransaction = bussinessMethod.getAnnotation(ProxyTransaction.class);
		transactionContext.setPropagation(proxyTransaction.propagation());
		transactionContext.setBusinessCallback(point::proceed);
		transactionInterceptor.doInvokeTransaction(transactionContext);
	}

}
